websocket @ServerEndpoint(value = "/websocket/{ip}")详解 | 您所在的位置:网站首页 › websocket sendobject › websocket @ServerEndpoint(value = "/websocket/{ip}")详解 |
WebSocket是JavaEE7新支持的: Javax.websocket.server包含注解,类,接口用于创建和配置服务端点 Javax.websocket包则包含服务端点和客户断电公用的注解,类,接口,异常 创建一个编程式的端点,需要继承Endpoint类,重写它的方法。 创建一个注解式的端点,将自己的写的类以及类中的一些方法用前面提到的包中的注解装饰(@EndPoint,@OnOpen等等)。 编程式注解示例: @Component @ServerEndpoint(value = "/websocket/{ip}") public class MyWebSocket { private static final Logger log = LoggerFactory.getLogger(MyWebSocket.class); // 静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。 private static int onlineCount = 0; // concurrent包的线程安全Map,用来存放每个客户端对应的MyWebSocket对象。 private static ConcurrentHashMap webSocketMap = new ConcurrentHashMap(); // 与某个客户端的连接会话,需要通过它来给客户端发送数据 private Session session; private String ip; // 客户端ip public static final String ACTION_PRINT_ORDER = "printOrder"; public static final String ACTION_SHOW_PRINT_EXPORT = "showPrintExport"; /** * 连接建立成功调用的方法 */ @OnOpen public void onOpen(Session session, @PathParam("ip") String ip) { this.session = session; this.ip = ip; webSocketMap.put(ip, this); addOnlineCount(); // 在线数加1 // System.out.println("有新连接加入!当前在线人数为" + getOnlineCount()); log.info("有新连接加入,ip:{}!当前在线人数为:{}", ip, getOnlineCount()); ExportService es = BeanUtils.getBean(ExportService.class); List list = es.listExportCodesByPrintIp(ip); ResponseData rd = new ResponseData(); rd.setAction(MyWebSocket.ACTION_SHOW_PRINT_EXPORT); rd.setList(list); sendObject(rd); } /** * 连接关闭调用的方法 */ @OnClose public void onClose(@PathParam("ip") String ip) { webSocketMap.remove(ip); // 从set中删除 // Map map = session.getPathParameters(); // webSocketMap.remove(map.get("ip")); subOnlineCount(); // 在线数减1 // System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount()); log.info("websocket关闭,IP:{},当前在线人数为:{}", ip, getOnlineCount()); } /** * 收到客户端消息后调用的方法 * * @param message * 客户端发送过来的消息 */ @OnMessage public void onMessage(String message, Session session) { // System.out.println("来自客户端的消息:" + message); log.debug("websocket来自客户端的消息:{}", message); OrderService os = BeanUtils.getBean(OrderService.class); OrderVo ov = os.getOrderDetailByOrderNo(message); // System.out.println(ov); ResponseData rd = new ResponseData(); ArrayList list = new ArrayList(); list.add(ov); rd.setAction(MyWebSocket.ACTION_PRINT_ORDER); rd.setList(list); sendObject(rd); // log.info("推送打印信息完成,单号:{}", ov.getOrderNo()); } /** * 发生错误时调用 */ @OnError public void onError(Session session, Throwable error) { // System.out.println("发生错误"); log.error("webSocket发生错误!IP:{}", ip); error.printStackTrace(); } /** * 像当前客户端发送消息 * * @param message * 字符串消息 * @throws IOException */ public void sendMessage(String message) { try { this.session.getBasicRemote().sendText(message); // this.session.getAsyncRemote().sendText(message); } catch (IOException e) { e.printStackTrace(); log.error("发送数据错误,ip:{},msg:{}", ip, message); } } /** * 向当前客户端发送对象 * * @param obj * 所发送对象 * @throws IOException */ public void sendObject(Object obj) { ObjectMapper mapper = new ObjectMapper(); mapper.setSerializationInclusion(Include.NON_NULL); String s = null; try { s = mapper.writeValueAsString(obj); } catch (JsonProcessingException e) { e.printStackTrace(); log.error("转json错误!{}", obj); } this.sendMessage(s); } /** * 群发自定义消息 */ public static void sendInfo(String message) { for (Entry entry : webSocketMap.entrySet()) { MyWebSocket value = entry.getValue(); value.sendMessage(message); } } public static synchronized int getOnlineCount() { return onlineCount; } public static synchronized void addOnlineCount() { MyWebSocket.onlineCount++; } public static synchronized void subOnlineCount() { MyWebSocket.onlineCount--; } public static ConcurrentHashMap getWebSocketMap() { return webSocketMap; } }当创建好一个(服务)端点之后,将它以一个指定的URI发布到应用当中,这样远程客户端就能连接上它了。 Websocket(服务)端点以URI表述,有如下的访问方式: ws://host:port/path?query wss://host:port/path?query 注解详解: @ServerEndPoint: RequiredElements : Value: URI映射 OptionalElemens: subprotocols: decoders:解码器 encoders:编码器 configurator 建立连接相关: Annotation Event Example OnOpen Connection opened @OnOpen Public void open(Sessionsession, EndpointConfig conf) { } OnMessage Message received @OnMessage public void message(Sessionsession, String msg) { } OnError Connection error @OnError public void error(Sessionsession, Throwable error) { } OnClose Connection closed @OnClose public void close(Sessionsession, CloseReason reason) { } Session代表着服务端点与远程客户端点的一次会话。 容器会为每一个连接创建一个EndPoint的实例,需要利用实例变量来保存一些状态信息。 Session.getUserProperties提供了一个可编辑的map来保存properties, 例如,下面的端点在收到文本消息时,将前一次收到的消息回复给其他的端点 @ServerEndpoint("/delayedecho") public class DelayedEchoEndpoint { @OnOpen public void open(Sessionsession) { session.getUserProperties().put("previousMsg", ""); } @OnMessage public void message(Session session, Stringmsg) { String prev= (String) session.getUserProperties().get("previousMsg"); session.getUserProperties().put("previousMsg",msg); try { session.getBasicRemote().sendText(prev); } catch (IOException e){ ... } } }发送、接收消息: Websocketendpoint能够发送和接收文本、二进制消息,另外,也可以发送ping帧和接收pong 帧 发送消息: Obtain the Session object from theconnection. 从连接中获得Session对象 Session对象是endPoint中那些被注解标注的方法中可得到的参数 当你的message作为另外的消息的响应 在@OnMessage标注的方法中,有session对象接收message 如果你必须主动发送message,需要在标注了@OnOpen的方法中将session对象作为实例变量保存 这样,你可以再其他方法中得到该session对象 1.Use the Session object to obtain aRemote Endpoint object. 通过Session对象获得Remoteendpoint对象 2.Use the RemoteEndpoint object to sendmessages to the peer. 利用RemoteEndpoint对象来发送message 代码示例: @ServerEndpoint("/echoall") public class EchoAllEndpoint { @OnMessage public void onMessage(Session session, Stringmsg) { try { for (Session sess :session.getOpenSessions()) { if (sess.isOpen()) sess.getBasicRemote().sendText(msg); } } catch (IOExceptione) { ... } } } 接收消息 OnMessage注解指定方法来处理接收的messages 在一个端点类中,至多可以为三个方法标注@OnMessage注解 消息类型分别为:text、binary、pong。
我们查看一下ServerEndpoint类源码: @Retention(value = RetentionPolicy.RUNTIME) @Target(value = {ElementType.TYPE}) public @interface ServerEndpoint { public String value(); public String[] subprotocols() default {}; public Class |
CopyRight 2018-2019 实验室设备网 版权所有 |